(function(){
    var $ = jQuery;


    /**
     * inherits function.
     */
    function inherits(defClass, parentClass) {
        function temp() {};
        temp.prototype = parentClass.prototype;
        defClass.super_ = parentClass.prototype;
        defClass.prototype = new temp();
        defClass.prototype.constructor = defClass;
    };

    
    var events = {};

    /**
     * It is addEventListener() alias.
     */
    events.listen = function(src, type, listener, capture) {
        var listener_ = function(e) {
            if(!dom.isElement(src)){
                if(!src.isEnabled()){
                    return;
                }
            }
            e.target = e.target || e.srcElement;
            listener.call(src, e);
        };

        var node = dom.isElement(src)? src: src.getElement();

        if(node.addEventListener){
            node.addEventListener(type, listener_, capture); 
        }else{
            node.attachEvent('on'+type, listener_); 
        }
    };


    /**
     * It is removeEventListener() alias.
     */
    events.unlisten = function(node, type, listener, capture){
        if(node.removeEventListener){
            node.removeEventListener(type, listener, capture);
        }else{
            node.detachEvent('on'+type, listener);
        }
    };


    var dom = {};


    dom.isElement = function(o) {
        if(typeof o === 'object'){
            return !!o.ELEMENT_NODE;
        }
        return false;
    }

    function dom_item(index){
        if(arguments.length < 1){
            throw Error('Not enough arguments');
        }
        return this.get(index);
    }

    dom.query = function(node, selector) {
        if(!node.querySelectorAll){
            return node.querySelectorAll(selector);
        }else{
            var o = $(selector, node);
            o.item = dom_item;
            return o
        }
    };

    dom.removeClass = function(node, className) {
        $(node).removeClass(className);
    };

    dom.addClass = function(node, className) {
        $(node).addClass(className);
    };


    /**
     * base for all ui element.
     */
    function Control(nodeType, className) {
        this.nodeType_ = nodeType || this.nodeType_;
        this.nodeClassName = className || this.nodeClassName;
    }
    Control.prototype.node_ = null;
    Control.prototype.nodeType_ = 'div';
    Control.prototype.nodeClassName = 'control';
    Control.prototype.isEnabled_ = true;
    Control.prototype.onClick = null;

    Control.prototype.getElement = function() {
        return this.node_;
    }

    Control.prototype.isEnabled = function(value) {
        return this.isEnabled_;
    }

    Control.prototype.setEnabled = function(value) {
        this.isEnabled_ = !!value;
        if(this.isEnabled_){
            dom.removeClass(this.node_, this.nodeClassName+'-disabled');
        }else{
            dom.addClass(this.node_, this.nodeClassName+'-disabled');
        }
    };

    Control.prototype.createNode = function() {
        var node = document.createElement(this.nodeType_);
        node.className = this.nodeClassName;
        return node;
    };

    Control.prototype.setContent = function(content) {
        this.node_.innerHTML = '';
        if(typeof content == 'string'){
            this.node_.innerHTML = content;
        }else if(dom.isElement(content)){
            this.node_.appendChild(content);
        }
    };

    Control.prototype.inDocument = function() {
        if(this.node_){
            return !!this.node_.parentNode;
        }
        return false;
    };

    Control.prototype.handleMouseOver_ = function(e) {
        dom.addClass(this.node_, this.nodeClassName+'-hover');
    };

    Control.prototype.handleMouseOut_ = function(e) {
        dom.removeClass(this.node_, this.nodeClassName+'-hover');
        dom.removeClass(this.node_, this.nodeClassName+'-active');
    };

    Control.prototype.handleMouseDown_ = function(e) {
        dom.addClass(this.node_, this.nodeClassName+'-active');
    };

    Control.prototype.handleMouseUp_ = function(e) {
        dom.removeClass(this.node_, this.nodeClassName+'-active');
    };

    Control.prototype.handleClick_ = function(e) {
        this.onClick(e);
    };

    Control.prototype.render = function(opt_parent) {
        if(this.inDocument()){
            throw Error('Control already rendered');
        }

        if(!this.node_){
            this.node_ = this.createNode();
        }

        if(opt_parent){
            opt_parent.appendChild(this.node_);
        }else{
            document.body.appendChild(this.node_);
        }

        events.listen(this, 'mouseover', this.handleMouseOver_);
        events.listen(this, 'mouseout', this.handleMouseOut_);
        events.listen(this, 'mousedown', this.handleMouseDown_); 
        events.listen(this, 'mouseup', this.handleMouseUp_);

        if(typeof this.onClick == 'function'){
            events.listen(this, 'click', this.handleClick_);
        }
    };

    Control.prototype.show = function() {
        this.node_.style.display = '';
    };

    Control.prototype.hide = function() {
        this.node_.style.display = 'none';
    };


    /**
     * button
     */
    function Button(caption){
        Control.call(this, 'span', 'button');
        if(!!caption){
            this.caption_ = caption;
        }
    }
    inherits(Button, Control);

    Button.prototype.caption_ = 'button';
    Button.prototype.setCaption = function(caption) {
        this.caption_ = caption;
        this.setContent(this.caption_);
    };
    
    Button.prototype.render = function(opt_parent) {
        Button.super_.render.call(this, opt_parent);
        this.setContent(this.caption_);
    };
    

    /**
     * popup element
     */
    function Popup() {
        Control.call(this, 'div', 'popup');
    }
    inherits(Popup, Control);

    Popup.prototype.render = function(opt_parent) {
        Popup.super_.render.call(this, opt_parent);
        this.node_.setAttribute('isPopup', true);
        var this_ = this;
        events.listen(document, 'mousedown', function(e){
            if(e.target.getAttribute('isPopup') || e.target.getAttribute('popupButton')){
                return;
            }
            this_.hide();
        });
    };


    /**
     * Dialog
     */
    function Dialog() {
        Control.call(this, 'div', 'dialog');
    }
    inherits(Dialog, Control);


    /**
     * export jsui
     */
    var jsui = this.jsui = {};
    jsui.events = events;
    jsui.dom = dom;
    jsui.Control = Control;
    jsui.Button = Button;
    jsui.Popup = Popup;
    jsui.Dialog = Dialog;
})();
